/*
 *
 *  Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
 *  SPDX-License-Identifier: Apache-2.0
 *
 */
import React, { Ref, useCallback, useEffect, useImperativeHandle, useState } from 'react';
import { Check, H3, Icon } from 'tea-component';

export type SelectedNodes = {
  text: string;
  value: string;
  options: {
    text: string;
    value: string;
  }[];
}[];

interface Props {
  title: string;
  data: {
    title: string;
    subTitle: string;
    options: SelectedNodes;
  };
  onChange: (data: SelectedNodes) => void;

  /**
   * 左侧选项选中回调
   */
  onLeftOptionClick?: (index: number) => void;
}

/**
 * 所有一级节点下的二级节点项合并为一维数组
 * @param nodes
 */
export function flatOptions(nodes: SelectedNodes) {
  return nodes.reduce(
    (
      res: {
        text: string;
        value: string;
      }[],
      item,
    ) => {
      if (item.options?.length) {
        return res.concat(item.options);
      }
      return res;
    },
    [],
  );
}

function buildNodeUniKey(
  leftItem: {
    text: string;
    value: string;
    options: {
      text: string;
      value: string;
    }[];
  },
  childItem: {
    text: string;
    value: string;
  },
): string {
  return leftItem.value + childItem.value;
}

export const SourceSelector = React.forwardRef(SourceSelectorContainer);

/**
 * 选择器
 */
function SourceSelectorContainer({ data, title, ...otherProps }: Props, parentRef: Ref<any>) {
  const [activeLeftIndex, setActiveLeftIndex] = useState(0);
  const handleLeftOptionClick = useCallback((index) => {
    setActiveLeftIndex(index);
    otherProps.onLeftOptionClick?.(index);
  }, []);

  const [selectedNodes, setSelectedNodes] = useState<SelectedNodes>([]); // 选中节点缓存
  const [selectedFlattenNodes, setFlattenSelectedNodes] = useState<Set<string>>(new Set()); // 选中节点缓存，用于标识选中状态

  useImperativeHandle(parentRef, () => ({
    updateSelectedNodes: (nodes: SelectedNodes) => setSelectedNodes(nodes),
    clearCache: () => {
      setSelectedNodes([]);
      setFlattenSelectedNodes(new Set());
      setActiveLeftIndex(0);
    },
  }));
  useEffect(() => {
    setFlattenSelectedNodes(
      selectedNodes.reduce((res, item) => {
        item.options.forEach((node) => {
          res.add(buildNodeUniKey(item, node));
        });
        return res;
      }, new Set<string>()),
    );
  }, [selectedNodes]);

  const handleNodeCheckChange = useCallback(
    (checked, _index, item) => {
      if (checked) {
        if (!selectedNodes[activeLeftIndex]) {
          selectedNodes[activeLeftIndex] = {
            text: data.options[activeLeftIndex].text,
            value: data.options[activeLeftIndex].value,
            options: [],
          };
        }
        selectedNodes[activeLeftIndex].options.push(item);
      } else {
        const findIndex = selectedNodes[activeLeftIndex].options.findIndex((node) => node.value === item.value);
        selectedNodes[activeLeftIndex].options.splice(findIndex, 1);
      }
      const newSelectedNodes = [...selectedNodes];
      setSelectedNodes(newSelectedNodes);
      otherProps?.onChange(newSelectedNodes);
    },
    [data],
  );

  /**
   * 针对selectedNodes，需要对于未初始化的数组进行初始化
   */
  useEffect(() => {
    let shouldUpdate = false;
    data.options.forEach((item, index) => {
      if (selectedNodes[index] === undefined) {
        shouldUpdate = true;
        selectedNodes[index] = {
          text: data.options[index].text,
          value: data.options[index].value,
          options: [],
        };
      }
    });
    shouldUpdate && setSelectedNodes([...selectedNodes]);
  }, [data.options]);

  return (
    <div>
      <H3>{title}</H3>
      <div className={'selector'}>
        <div className="flex title">
          <div className="item1">{data.title}</div>
          <div className="item2">{data.subTitle}</div>
        </div>
        <div className="flex">
          <div className="item1 body selector-body-left">
            {data.options.map((item, index) => (
              <div
                key={item.value}
                className={index === activeLeftIndex ? 'selected' : ''}
                onClick={() => handleLeftOptionClick(index)}
              >
                {item.text}
              </div>
            ))}
          </div>
          <div className="item2 body">
            {data.options[activeLeftIndex]?.options.map((item, index) => (
              <div key={item.value}>
                <Check
                  type={'checkbox'}
                  value={selectedFlattenNodes.has(buildNodeUniKey(data.options[activeLeftIndex], item))}
                  onChange={(checked) => handleNodeCheckChange(checked, index, item)}
                >
                  <span className={'tea-ml-1n'}>{item.text}</span>
                </Check>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

export function TargetSelector({ data, title, ...otherProps }: Props) {
  const [activeLeftIndex, setActiveLeftIndex] = useState(0);
  const handleLeftOptionClick = useCallback((index) => {
    setActiveLeftIndex(index);
  }, []);

  const [selectedNodes, setSelectedNodes] = useState<SelectedNodes>([]); // 选中节点缓存

  const [optionsFiltered, setOptionsFiltered] = useState<SelectedNodes>([]);

  useEffect(() => {
    setSelectedNodes(data.options);
    setOptionsFiltered(data.options.filter((item) => item.options.length > 0));
  }, [data.options]);

  const handleClear = useCallback(
    (index) => {
      optionsFiltered[activeLeftIndex]!.options.splice(index, 1);
      const newSelectedNodes = [...selectedNodes];
      setSelectedNodes(newSelectedNodes);
      otherProps?.onChange(newSelectedNodes);
    },
    [selectedNodes, optionsFiltered, activeLeftIndex],
  );

  return (
    <div>
      <H3>{title}</H3>
      <div className={'selector'}>
        <div className="flex title">
          <div className="item1">{data.title}</div>
          <div className="item2">{data.subTitle}</div>
        </div>
        <div className="flex">
          <div className="item1 body selector-body-left">
            {optionsFiltered.map((item, index) => (
              <div
                key={item.value}
                className={index === activeLeftIndex ? 'selected' : ''}
                onClick={() => handleLeftOptionClick(index)}
              >
                {item.text}
              </div>
            ))}
          </div>
          <div className="item2 body">
            {optionsFiltered[activeLeftIndex]?.options.map((item, index) => (
              <div key={item.value} className={'selector-clear-item'}>
                <div>{item.text}</div>
                <Icon type="dismiss" onClick={() => handleClear(index)} />
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}
